const rootCheck = require('root-check') // 1.0.0版本不会报es6 modules错误
const userHome = require('user-home') // 用户目录
const semver = require('semver')
const colors = require('colors/safe') // 更改 error 中文字颜色
const dotenv = require('dotenv')
const pathExists = require('path-exists').sync
const commander = require('commander')

const path = require('path')

const log = require('@lenovo-cli/log')
const dynaExec = require('@lenovo-cli/dyna-exec')

const package = require('../package.json')
const { CLI_DEFAULT_DIR } = require('./const')

module.exports = async () => {
  try {
    await cliCheck()
    registerCommand()
  } catch (e) {
    log.error(e.message)
  }
}
async function cliCheck() {
  // 检查版本号功能
  log.info('cli', package.version)
  // 检查root账户， 进行root降级(修改uid)
  rootCheck()
  // 检查用户目录功能
  if (!userHome || !pathExists(userHome)) {
    // 用户不存在的话抛出一场
    throw new Error(colors.red('当前登录用户主目录不存在！'))
  }
  // 检查环境变量
  const dotevnPath = path.resolve(userHome, '.env') // 解析 .env 文件

  if (pathExists(dotevnPath)) {
    dotenv.config({
      path: dotevnPath,
    })
  }

  // 构建环境变量
  const cliConfig = {
    home: userHome,
  }
  cliConfig['cliHome'] = process.env.CLI_HOME
    ? path.join(userHome, process.env.CLI_HOME)
    : path.join(userHome, CLI_DEFAULT_DIR)
  process.env.CLI_HOME_PATH = cliConfig.cliHome // 将生成的新的环境变量更新在 .env 文件中
  // 检查脚手架版本是否需要更新
  const currentVersion = package.version
  const npmName = package.name
  // 调用npm API，获取所有版本号
  const { fetchSemverVersions } = require('@lenovo-cli/fetch-pkg-info')
  // 提取所有版本号，比对哪些版本号是大于当前版本号
  const lastVersion = await fetchSemverVersions(currentVersion, npmName)
  // 获取最新版本号与当前版本比对，若最新版本号>当前版本号，给出提示更新
  if (lastVersion && semver.gt(lastVersion, currentVersion)) {
    log.warn(
      colors.yellow(`当前版本：${currentVersion}，最新版本：${lastVersion}，请手动更新  ${npmName}
         更新命令： npm install -g ${npmName}`)
    )
  }
}

// 注册命令功能
function registerCommand() {
  const cli = new commander.Command() // 实例化脚手架
  cli
    .name(Object.keys(package.bin)[0])
    .usage('<commmand> [options]')
    .version(package.version)
    .option('-d, --debug', '是否开启debug模式', false)
    .option('-tp, --targetPath <targetPath>', '是否指定本地调试文件路径', '')

  cli
    .command('init [projectName]')
    .option('-f,--force', '是否强制初始化项目')
    .action(dynaExec) // dynaExec: 因为init命令以外还会用到，它的参数不可控，所以参数的获取在dynaExec内部，而不是调用时传入 ！！！

  cli
    .command('publish')
    .option('--update', '强制更新远程Git仓库')
    .option('--token', '强制更新远程仓库的token')
    .option('--type', '强制更新远程仓库的类型')
    .option('--buildCmd <buildCmd>', '构建命令')
    .option('--prod', '是否正式发布')
    .option('--sshUser <sshUser>', '模版服务器用户名') // 命令输入格式：--sshUser root --sshIp 10.122.190.68 --sshPath /xxx/xx/xxx/xxx
    .option('--sshIp <sshUser>', '模版服务器IP或域名') // 上传的服务器地址
    .option('--sshPath <sshPath>', '模版服务器上传路径') // 上传的服务器地址
    .action(dynaExec)

  cli.on('option:debug', function () {
    if (cli.opts().debug) {
      process.env.LOG_LEVEL = 'verbose'
    } else {
      process.env.LOG_LEVEL = 'info'
    }
    log.level = process.env.LOG_LEVEL
  })

  // 指定环境变量 targetPath
  cli.on('option:targetPath', function () {
    process.env.CLI_TARGET_PATH = cli.opts().targetPath // 储存到全局环境变量中，多进程都能使用\
  })
  // 对未知命令的监听
  cli.on('command:*', function (obj) {
    const availableCommands = cli.commands.map(cmd => cmd.name())
    console.log(colors.red('未注册的指令：' + obj[0]))
    if (availableCommands.length > 0) {
      console.log(colors.green('可用指令：' + availableCommands.join(',')))
    }
  })

  if (process.argv.length < 3) {
    // lenght小于3，说明没有输入命令，提示帮助文档
    cli.outputHelp()
    console.log() // 底部增加一空行
  } else {
    cli.parse(process.argv)
  }
}

process.on('unhandledRejection', (reason, p) => {
  // 我刚刚不活了一个未处理的promise rejection，因为我们已经有了对于未处理错误的后备处理机制，直接抛出，让它来处理
  throw reason
})

process.on('uncaughtException', error => {
  // 我刚收到一个从未被处理的错误，现在处理它，并决定是否要重启应用
  console.log('uncaughtException', error)
  process.exit(1)
})

// throw new Error('出错了') 测试上面全局未catch的错误
